import 'reflect-metadata'
import { StoreOptions, Module } from 'vuex'
import { StoreItem, StoreDecBuilder } from "./store-dec-builder";
import Vue from 'vue';


export class StoreWithRoot<TRoot>{
    root?: TRoot
}

export function StoreModule(): ClassDecorator {
    return target => {

        //let p = new Proxy(target, {});

        /** 模块的定义，用于输入到 vuex 的模块定义 */
        //let module_definition = {} as StoreOptions<_state>;

        // let store_context = new StoreContext;
        // let store_item = StoreItem.CreateWithModule(module_definition);

        let store_builder = new StoreDecBuilder();

        let prototype_names = Object.getOwnPropertyNames(target.prototype);
        //_.pullAll(prototype_names, ["root", "constructor"]);
        let exclude_keys = ["root", "constructor"];

        for (let key of prototype_names) {
            //let key = prototype_names[idx];
            if (exclude_keys.includes(key)) continue;

            let desc = Reflect.getOwnPropertyDescriptor(target.prototype, key);
            if (desc) {
                if (typeof desc.value == "function") {
                    store_builder.__appendAction(key, desc.value);
                } else {
                    if (typeof desc.get == "function") {
                        store_builder.__appendGetter(key, desc.get);
                    }
                    if (typeof desc.set == "function") {
                        store_builder.__appendMutation(key, desc.set);
                    }
                }
            }
        }

        let v = Reflect.construct(target, []);
        for (let key in v) {
            if (key == "root") continue;
            let desc = Reflect.getOwnPropertyDescriptor(v, key);
            if (desc) {
                if (typeof desc.value == "object") {
                    let vp = Reflect.getPrototypeOf(desc.value).constructor;
                    if (Reflect.hasOwnMetadata("store:item", vp) || Reflect.hasOwnMetadata("store:module", vp)) {
                        let store_item = Reflect.getMetadata("store:item", vp) as StoreItem;
                        let module_item = Reflect.getMetadata("store:module", vp) as Module<any, any>;
                        store_builder.__appendModule(key, store_item, module_item);
                    }
                    else {
                        store_builder.__appendState(key, desc.value);
                    }
                }
                else {
                    store_builder.__appendState(key, desc.value);
                }
            }
        }

        // 保存两个对象
        let { module_item, store_item } = store_builder.output;
        // module_definition 该对象用于输送给 vuex 用于组建状态
        Reflect.defineMetadata("store:module", module_item, target);
        // store_item 该对像用于给开发者调用 vuex 状态的中间对象
        Reflect.defineMetadata("store:item", store_item, target);
    };
}

/**
 * 向VUE安装对应插件
 * @param param0 用于安装的选项
 */
export function StoreClassInstall(
    { name, store_type }: { name: string, store_type: Object }
): ({
    module_item?: StoreOptions<{ [key: string]: any }>,
    store_item?: StoreItem
}) {
    let module_item: StoreOptions<{ [key: string]: any }> | undefined = Reflect.getMetadata("store:module", store_type);
    let store_item: StoreItem | undefined = Reflect.getMetadata("store:item", store_type);

    if (module_item && store_item) {
        module_item.plugins = [_store => {
            store_item && store_item.__init(_store);
            _store.subscribe
        }];
    }

    Vue.use(v => {
        Object.defineProperty(Vue.prototype, name,
            {
                writable: false,
                value: store_item
            }
        );
    });

    return { module_item, store_item }
}